const JOIN_KEY = '_';

function fullPathSort(v1, v2) {
  if (v1 === null) {
    return -1;
  }

  if (v2 === null) {
    return 1;
  }

  return v1.fullPath.localeCompare(v2.fullPath);
}

function cartesianProductOf(list, isFilter = false, isSort = true) {
  return Array.prototype.reduce.call(
    list,
    (a, b) => {
      let ret = [];
      a.forEach((item1) => {
        b.forEach((item2) => {
          let arr = item1.concat([item2]);

          if (isFilter) {
            arr = arr.filter((v) => {
              return v !== null;
            });
          }

          if (isSort) {
            arr = arr.sort((v1, v2) => {
              return fullPathSort(v1, v2);
            });
          }

          ret.push(arr);
        });
      });
      return ret;
    },
    [[]],
  );
}

function transformOptions(str) {
  let options;

  if (!str) {
    return [];
  }

  if (typeof str === 'object') {
    options = str;
  } else {
    options = JSON.parse(str);
  }

  return Object.keys(options).map((key) => {
    return options[key].map((v) => {
      return {
        name: key,
        value: v,

        fullPath: `${key}${JOIN_KEY}${v}`,
      };
    });
  });
}

function transformSoldList(str) {
  let options;

  if (!str) {
    return [];
  }

  if (typeof str === 'object') {
    options = str;
  } else {
    options = JSON.parse(str);
  }

  return options.map((o) => {
    return Object.keys(o)
      .map((key) => {
        return {
          name: key,
          value: o[key],

          fullPath: `${key}${JOIN_KEY}${o[key]}`,
        };
      })
      .sort((v1, v2) => {
        return fullPathSort(v1, v2);
      });
  });
}

function option2path(option) {
  return option
    .map(({ fullPath }) => {
      return fullPath;
    })
    .join(JOIN_KEY);
}

function checkIsSold(option, soldPathArr) {
  return soldPathArr.find((soldPath) => {
    return soldPath === option2path(option);
  });
}

function getPathStock(optionsStr, soldStr) {
  // 将 {"产地": ["上海", "北京"], "净含量": ["10", "20"]} 转换为
  /* [
      [ {"name":"产地","value":"上海","fullPath":"产地_上海"},
        {"name":"产地","value":"北京","fullPath":"产地_北京"}
      ],
      [ {"name":"净含量","value":"10","fullPath":"净含量_10"},
        {"name":"净含量","value":"20","fullPath":"净含量_20"}
      ]
    ]
  */
  const allOptions = transformOptions(optionsStr);

  // 将 [{"产地":"上海","净含量":"10"},{"产地":"上海","净含量":"20"}] 转换为
  /*
        [
          [  {"name":"产地","value":"上海","fullPath":"产地_上海"},
             {"name":"净含量","value":"10","fullPath":"净含量_10"}
          ],
          [  {"name":"产地","value":"上海","fullPath":"产地_上海"},
             {"name":"净含量","value":"20","fullPath":"净含量_20"}
          ]
        ]
  */
  const soldArr = transformSoldList(soldStr);

  // 转换为 ["产地_上海_净含量_10","产地_上海_净含量_20"]
  const soldPathArr = soldArr.map((soldOption) => {
    return option2path(soldOption);
  });

  // 把规格每一种组合列出来
  let optionList = cartesianProductOf(allOptions);
  // 把规格每一种路径列出来, 即 只点击了一次规格, 点击了2次的规格
  let pathList = cartesianProductOf(
    allOptions.map((v) => {
      return [...v, null];
    }),
    true,
  );

  // 标注每一种组合的库存, 存在库存的标记为 1
  let optionWithInfo = optionList.map((option) => {
    const isSold = checkIsSold(option, soldPathArr);

    return {
      option,
      path: option2path(option),
      stock: isSold ? 0 : 1,
    };
  });

  // 标注每条路径的库存
  let pathWithInfo = pathList.map((item) => {
    const includeList = optionWithInfo.filter(({ option }) => {
      return item.every(({ fullPath }) => {
        return option.find(({ fullPath: optionFullPath }) => {
          return fullPath === optionFullPath;
        });
      });
    });

    return {
      option: item,
      stock: includeList.reduce((result, v) => {
        result += v.stock;
        return result;
      }, 0),

      children: includeList,
    };
  });

  let pathWithStock = pathWithInfo.reduce((result, { option, stock }) => {
    result[
      option
        .map(({ fullPath }) => {
          return fullPath;
        })
        .join(JOIN_KEY)
    ] = stock;
    return result;
  }, {});

  return {
    stockPath: pathWithStock,
    optionList,
  };
}

/**
 * options: {"产地": ["上海", "北京"], "净含量": ["10", "20"]}
 * sold:   [{"产地":"上海","净含量":"10"},{"产地":"上海","净含量":"20"}]
 */
function calculateStockPath(options, sold) {
  return getPathStock(options, sold);
}

export { JOIN_KEY, calculateStockPath };
